一個網頁頁面能不能讓你看到,取決於你有沒有被認證,或者這個頁面需不需要認證 ?
比方說你正在瀏覽一個公開的 GitHub 專案,你只需要一個簡單的 GET 方法就能看到頁面。
但如果你想要修改這個專案,那就會牽扯到一個認證議題 : 你是不是該專案的擁有者或協作者 ?
即使你有權限專案內容,那你也必須先被認證你有權限修改。最常見的驗證手法,當然就是登入了。
實際上 HTTP 是一個沒有狀態的網路協定。
上一秒鐘你才發送一個登入網頁的封包過去,下一秒你想存取私人頁面的時候,其實對方根本不知道你是誰 ?
這個特性是與真實世界情況有衝突的。平常我們打開網頁,至少可以保證好幾個月,甚至到換電腦前,我們的網頁都保持登入狀態。
這是因為有 HTTP Headers 的存在,而 HTTP Headers 又存在一個東西叫 Cookies。
事實上,就算有了 Cookies 也無法改變 HTTP 協定就是無狀態這件事情本身。
但是換個角度想,如果客戶端和伺服器端都把 Cookies 存起來,然後讓客戶端每次請求都帶著,其實就解決了 HTTP 無狀態的問題。
Cookies 跟 Session 算是一個比較常被拿來一起討論的東西。
很多文章會告訴你 :「這兩者個差別在於,Cookies 是放在客戶端,Session 則放在伺服器端,所以 Session 的安全性比較高。」
這句話是對的,但光是這樣,聽完很令人費解。
事實上,在完成一連串的驗證步驟後,不管是 Cookies 或 Session 都會由伺服器端去頒發給你。
比方說,你登入網站後,所以伺服器端回傳了 { login : true, is_admin : false } 的 Cookies 給你。
因為你不是管理員,所以你看不見管理員能存取的頁面,這是理所當然的。我們可以發現驗證點就是 is_admin。
這時候我們不難想到,「那如果把 is_admin 改成 true,我是不是就通過驗證了 ?」這就是 Cookies 放在客戶端,它不安全的點。
如果今天伺服器端回傳的是 { session-id : 494a26976898318aef09eb3af47b2f93 },而隱私資料存放在伺服器端就安全許多。
因為伺服器端會先以 session-id 驗證你是誰 ? 接下來才去驗證你的其他隱私資料。
494a26976898318aef09eb3af47b2f93 是 Yotsuba 的 MD5 值。
當然一般情況下,網站的 Session 生成不會用那麼簡單的算法。
你會發現,其實 session-id 也是必須被存放在客戶端的 Cookies,差別在於隱私資料是放在伺服器端。
所謂「Cookies 放在客戶端,Session 放在伺服器端,所以 Session 的安全性比較高。」的道理其實在這裡。
再舉個簡單的例子,「我是 Yotsuba,我的錢包有 1000 元。」
這些資料如果直接存在 Cookies,那我就有機會直接修改 Cookies 的裡面的金額。
但如果 Cookies 只存在「我是 Yotsuba」這筆資料,伺服器端會先根據 Cookies 檢查我是誰,才去檢查 Yotsuba 這個人的錢包,相較之下就沒有風險。
回到最根本的問題,就是如何讓我們的爬蟲像個人類一樣 ?
如果你看完了上面的篇幅,你會發現不管是 Cookies 或 Session 的形式,一旦誰取得了,誰就代表著誰。
我有我的 Cookies,所以我就是我 ; 我有你的 Cookies,那麼我也能偽裝成你了 ; 而爬蟲有了我的 Cookies,爬蟲就能像個人類了。
無論如何,網站 Cookies 的外洩都代表著風險。
把 Cookies 餵給自家爬蟲不算外洩,因為那是自己在偽裝成自己。
這一切都要從 HTTP Headers 講起。
當我們知道 HTTP 是無狀態的協定,且能賦予它狀態的又是 HTTP Headers 的,其實大方向上就把認證議題給講完了。
在 Headers 有一個最常見的內容叫 User-Agent ( 簡稱 UA ),他通常會長的像是 :
User-Agent : Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0
寫爬蟲的時候,如果無法正常被認證,我會第一個懷疑到的驗證點就是 User-Agent。
每個 HTTP 客戶端程式,通常都會有自己獨特的 User-Agent,剛才的範例是我的 Firefox 瀏覽器使用的 User-Agent。
curl 會顯示 curl/7.74.0,Python requests,Python requests 會顯示 python-requests/2.26.0。
這個 Headers 通常存放著 Token,但是 Token 又分成非常多種,Basic Token、Bearer Token 或 JWT Token 等等 ...
而且 Headers 在名字上也沒有規定一定要使用 Authorization 這個欄位,也有可能就叫 Token 或其他名字。
和 Authorization 一樣比較沒有規則性,完全要取決於網站的實作。
值得高興的是,大部分時候爬蟲專注在處理怎麼讓送出去的表單保持正確,而不是手動處理好 Cookies。
詳細的部份會在後面的篇幅慢慢提到。
IP 不只影響了爬蟲的驗證,就連平常你使用瀏覽器上網也會受到影響,而且顯而易見。
比方說,如果有網頁告訴你 :「你的地區無法無法存取這個頁面」,那就非常有可能,是網站判斷你的 IP 來自於海外,所以禁止存取。
關於 IP 的情況還有非常多種,比方說你不小心瀏覽到私人網路,或者你不小心觸碰到會被網站 Ban 掉 IP 的規則等等。
這部份和以上的驗證議題稍有不同,大部分時候我們專注於如何讓爬蟲像人類 ? 而不是專注於如何爬取一個我們已經被 Ban 掉的網站 ?